﻿#region Imports
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Timers;
using System.Windows;
using System.Windows.Media;
using CommonUtilities.Commands;
using CommonUtilities.Extensions;
using CommonUtilities.Util;
using Microsoft.VisualBasic;
using MineSweeper.Models;
#endregion Imports

namespace MineSweeper.ViewModels
{
    public class MainViewModel : BaseViewModel
    {
        #region Declarations
        private readonly Timer timeKeeper = new Timer(100);
        List<int> mineIds = new List<int>();
        #endregion Declarations

        #region Properties
        public RelayCommand RefreshCodeCommand { get; private set; }
        public RelayCommand<Block> BlockClickCommand { get; private set; }
        public RelayCommand<Block> FlagCommand { get; private set; }

        private ObservableCollection<int> _RowValues = new ObservableCollection<int>();
        public ObservableCollection<int> RowValues
        {
            get { return _RowValues; }
            set { _RowValues = value; RaisePropertyChanged("RowValues"); }
        }

        private int _RowCount;
        public int RowCount
        {
            get { return _RowCount; }
            set { _RowCount = value; RaisePropertyChanged("RowCount"); }
        }

        private int _ColumnCount;
        public int ColumnCount
        {
            get { return _ColumnCount; }
            set { _ColumnCount = value; RaisePropertyChanged("ColumnCount"); }
        }

        private int _GridRowCount;
        public int GridRowCount
        {
            get { return _GridRowCount; }
            set { _GridRowCount = value; RaisePropertyChanged("GridRowCount"); }
        }

        private ObservableCollection<Block> _Blocks;
        public ObservableCollection<Block> Blocks
        {
            get { return _Blocks; }
            set { _Blocks = value; RaisePropertyChanged("Blocks"); }
        }

        private int _BlockCount;
        public int BlockCount
        {
            get { return _BlockCount; }
            set
            {
                if (_BlockCount != value) timeKeeper.Stop();

                _BlockCount = value; RaisePropertyChanged("BlockCount");
                MineCount = Convert.ToInt32(_BlockCount * 0.15);
            }
        }

        private int _MineCount;
        public int MineCount
        {
            get { return _MineCount; }
            set { _MineCount = value; RaisePropertyChanged("MineCount"); }
        }

        private DateTime _StartTime;
        public DateTime StartTime
        {
            get { return _StartTime; }
            set { _StartTime = value; RaisePropertyChanged("StartTime"); }
        }

        private string _ElapsedTime;
        public string ElapsedTime
        {
            get { return _ElapsedTime; }
            set { _ElapsedTime = value; RaisePropertyChanged("ElapsedTime"); }
        }
        #endregion Properties

        #region Constructors
        public MainViewModel()
        {
            timeKeeper.Elapsed += new ElapsedEventHandler(timeKeeper_Elapsed);

            RefreshCodeCommand = new RelayCommand((param) => { RefreshBlocks(); });
            BlockClickCommand = new RelayCommand<Block>((param) => { BlockClicked(param); });
            FlagCommand = new RelayCommand<Block>((param) => { if (param.MarkedBomb) MineCount -= 1;if(param.MarkedSafe) });

            ObservableCollection<int> rowValues = new ObservableCollection<int>();
            for (int i = 1; i <= 10; i++) rowValues.Add(i);
            RowValues = rowValues;

#if DEBUG
            RowCount = 6; ColumnCount = 8; RefreshCodeCommand.Execute(null);
#endif
        }
        #endregion Constructors

        #region Events
        private void timeKeeper_Elapsed(object sender, ElapsedEventArgs e)
        {
            var elapsed = DateTime.Now - StartTime;
            ElapsedTime = Strings.Right(Strings.Left(elapsed.ToString(), 12), 9);
        }
        #endregion Events

        #region Methods
        void BlockClicked(Block block)
        {
            if (block.IsMine) { block.BlockBackground = Brushes.Orange; MessageBox.Show("BOOM!! Game Over!"); } // RKD
            else block.BlockBackground = Brushes.LightGreen;
        }

        private void RefreshBlocks()
        {
            BlockCount = RowCount * ColumnCount;
            if (BlockCount > 0)
            {
                if (!timeKeeper.Enabled) { StartTime = DateTime.Now; timeKeeper.Start(); }

                mineIds = new List<int>();
                Random r = new Random();
                for (int i = 0; i < MineCount; i++)
                {
                    int id;
                    do { id = r.Next(BlockCount); }
                    while (mineIds.Contains(id));

                    mineIds.Add(id);
                }

                var blocks = new ObservableCollection<Block>();
                for (int i = 0; i < BlockCount; i++)
                {
                    blocks.Add(new Block
                    {
                        Id = i,
                        RowId = i / ColumnCount,
                        ColumnId = i % ColumnCount,
                        IsMine = mineIds.Contains(i),
                    });
                }

                blocks.ForEach(b =>
                {
                    b.Left = (b.ColumnId == 0 ? -1 : b.Id - 1);
                    b.Top = (b.RowId == 0 ? -1 : b.Id - ColumnCount);
                    b.Right = (b.ColumnId == ColumnCount - 1 ? -1 : b.Id + 1);
                    b.Bottom = (b.RowId == RowCount - 1 ? -1 : b.Id + ColumnCount);
                });

                blocks.ForEach(b =>
                {
                    b.DiagLT = (b.Left == -1 || b.Top == -1 ? -1 : b.Top - 1);
                    b.DiagRT = (b.Right == -1 || b.Top == -1 ? -1 : b.Top + 1);
                    b.DiagRB = (b.Right == -1 || b.Bottom == -1 ? -1 : b.Bottom + 1);
                    b.DiagLB = (b.Left == -1 || b.Bottom == -1 ? -1 : b.Bottom - 1);
                });

                blocks.ForEach(b =>
                {
                    b.AdjMineCount = blocks.Where(z => z.IsMine
                        && (z.Left == b.Id || z.Top == b.Id || z.Right == b.Id || z.Bottom == b.Id
                        || z.DiagLT == b.Id || z.DiagRT == b.Id || z.DiagRB == b.Id || z.DiagLB == b.Id)).Count();
                });

                Blocks = blocks;
                GridRowCount = RowCount;
            }
        }
        #endregion Methods
    }
}
